﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Common;

namespace DriverEnvi
{

    /// <summary>
    /// An envi driver module that 
    /// 1. opens and registers a port
    /// 2. reads the active power consumption of an appliance from the USB port whenever it is available
    /// 3. Notifies applications that subscribed to this port
    /// </summary>

    [System.AddIn.AddIn("DriverEnvi")]
    public class DriverEnvi : Common.ModuleBase
    {
        private Port enviPort;
        private SerialPort serialport;
        private const string PORTNUM = "COM18";

        public override void Start()
        {
            logger.Log(" We Started: {0}", ToString());

            // ..... initialize the list of roles we are going to export
            List<View.VRole> listRole = new List<View.VRole>();

            RoleSensor enviRole = new RoleSensor();
            listRole.Add(enviRole);

            //.................instantiate the port
            View.VPortInfo portInfo = GetPortInfoFromPlatform("envi");
            enviPort = InitPort(portInfo);

            //..... bind the port to roles and delegates
            BindRoles(enviPort, listRole, null);

            //.................register the port after the binding is complete
            RegisterPortWithPlatform(enviPort);

            ReadFromSerialPort();
        }

        private void ReadFromSerialPort()
        {
            //foreach (String sport in SerialPort.GetPortNames())
            //{     
            //    try
            //    {
            //        serialport = new SerialPort(sport, 57600, Parity.None, 8, StopBits.One);

            //        // Close the serial port if it is open
            //        if (serialport.IsOpen)
            //        {
            //            serialport.Close();
            //        }
            //        // Open the serial port again
            //        serialport.Open();
            //        break;
            //    }
            //    catch (System.IO.IOException)
            //    {
            //        logger.Log("Try openning another port");
            //        continue;
            //    } 
            //}

            serialport = new SerialPort(PORTNUM, 57600, Parity.None, 8, StopBits.One);
            try
            {
                // Close the serial port if it is open
                if (serialport.IsOpen)
                {
                    serialport.Close();
                }
                // Open the serial port again
                serialport.Open();
            }
            catch (System.IO.IOException)
            {
                logger.Log("Error: failed to open {0} port", PORTNUM);
                logger.Log("Terminating execution of the DriverEnvi module");
                return;
            }


            // Defining the event handler function
            
            serialport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

            // Now we should wait for the DataReceived event
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
        }

        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int value = 0;
            Regex measurements = new Regex(@".+<watts>(\d+)</watts>.+<watts>(\d+)</watts>.+");
            String str = serialport.ReadLine();
            Match m = measurements.Match(str);
            if (m.Success)
            {
                int ch1 = Convert.ToInt32(m.Groups[1].Value);
                //Console.WriteLine(ch1);
                int ch2 = Convert.ToInt32(m.Groups[2].Value);
                //Console.WriteLine(ch2);

                // Adding power consumptions of both channels, the result is the total power consumption
                value = ch1 + ch2;

                // Setting the return parameter
                IList<View.VParamType> retVals = new List<View.VParamType>();
                retVals.Add(new ParamType(ParamType.SimpleType.integer, "", value, "value"));

                // Notifying modules (e.g., AppEnvi) subscribed to the enviPort
                enviPort.Notify(RoleSensor.RoleName, RoleSensor.OpGetName, retVals);

                logger.Log("{0}: issued notification for serial port {1}, reading value {2}", ToString(), PORTNUM, value.ToString());
            }
            else
            {
                // Pattern mismatch
                logger.Log("{0} is not a valid measurment data", str);
                //Console.WriteLine(str + " is not a valid measurment data");
            }
        }

        public override void Stop()
        {
            Finished();
        }

        public override void PortRegistered(View.VPort port)
        {
            //logger.Log("{0} got registeration notification for {1}", ToString(), port.ToString());
            //throw new NotImplementedException();
        }

        public override void PortDeregistered(View.VPort port)
        {
            //logger.Log("{0} deregistered port {1}", this.ToString(), port.GetInfo().ModuleFacingName());
            //throw new NotImplementedException();
        }

    }
}
